/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.stateless.MRP.ProductionPlan;

import entity.MRP.ProductionPlan.PlannedMonthlyDemand;
import entity.MRP.ProductionPlan.PlannedWeeklyDemand;
import entity.MRP.SaleForecast.MonthlySaleForecast;
import entity.MRP.SaleForecast.SaleForecastLineItem;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import session.stateless.HolidayBeanLocal;
import session.stateless.MRP.SaleForecast.SaleForecastBeanLocal;

/**
 *
 * @author zhozho
 */
@Stateless
public class MonthlyProductionPlanBean implements MonthlyProductionPlanBeanLocal {

    @PersistenceContext 
    private EntityManager em;
    @EJB
    SaleForecastBeanLocal saleForecastBeanLocal;
    @EJB
    WeeklyProductionPlanBeanLocal weeklyProductionPlanBeanLocal;
    @EJB
    HolidayBeanLocal holidayBeanLocal;
    
    public PlannedMonthlyDemand createPlannedMonthlyDemand(String month, Long productionPlan, 
            Long inventoryA, Long inventoryB, Long inventoryC, Long inventoryD, 
            Double breakDownA, Double breakDownB, Double breakDownC, Double breakDownD)
    {
        PlannedMonthlyDemand plannedMonthlyDemand = new PlannedMonthlyDemand();
        plannedMonthlyDemand.setMonthName(month);
        plannedMonthlyDemand.setProductionPlan(productionPlan);
        
        plannedMonthlyDemand.setInventoryA(inventoryA);
        plannedMonthlyDemand.setInventoryB(inventoryB);
        plannedMonthlyDemand.setInventoryC(inventoryC);
        plannedMonthlyDemand.setInventoryD(inventoryD);
        
        plannedMonthlyDemand.setBreakDownA(breakDownA);
        plannedMonthlyDemand.setBreakDownB(breakDownB);
        plannedMonthlyDemand.setBreakDownC(breakDownC);
        plannedMonthlyDemand.setBreakDownD(breakDownD);
        
        plannedMonthlyDemand.setWorkingHours(0);
        plannedMonthlyDemand.setOvertimeHours(0);
        
        Long noWorkingDays = new Long(getWorkingDaysByMonth(month));
        plannedMonthlyDemand.setNumberOfWorkingDays(noWorkingDays);
        
        //set production plans
        if ((productionPlan != null) && (breakDownA != null))
        {
            plannedMonthlyDemand.setProductionPlanA(Math.round((double) productionPlan * breakDownA/100));
        }
        
        if ((productionPlan != null) && (breakDownB != null))
        {
            plannedMonthlyDemand.setProductionPlanB(Math.round((double) productionPlan * breakDownB/100));
        }
        
        if ((productionPlan != null) && (breakDownC != null))
        {
            plannedMonthlyDemand.setProductionPlanC(Math.round((double) productionPlan * breakDownC/100));
        }
        
        if ((productionPlan != null) && (breakDownD != null))
        {
            plannedMonthlyDemand.setProductionPlanD(Math.round((double) productionPlan * breakDownD/100));
        }
        
        //set total capacity
        plannedMonthlyDemand.setTotalCapacity(2 * 8 * noWorkingDays);
        //set utilization
        
        if (productionPlan != null)
        {
            Double temp = (((double) (plannedMonthlyDemand.getProductionPlanA()+plannedMonthlyDemand.getProductionPlanB()) / plannedMonthlyDemand.getCapacityAB() 
                    + (double) (plannedMonthlyDemand.getProductionPlanC() + plannedMonthlyDemand.getProductionPlanD()) / plannedMonthlyDemand.getCapacityCD()) 
                    / plannedMonthlyDemand.getTotalCapacity()) * 100;
            plannedMonthlyDemand.setUtilization(Math.round(temp));
        }
        //month map index: 0 - Jan, 11 - Dec
        int monthName = Integer.parseInt(month.substring(0, month.length() - 5));
        int year = Integer.parseInt(month.substring(month.length() - 4));
        int monthIndex = monthName-1;

        List<MonthlySaleForecast> monthlySaleForecast = saleForecastBeanLocal.getMonthlySaleForecasts(year, monthIndex, monthIndex);
        List<SaleForecastLineItem> saleForecastLineItems = monthlySaleForecast.get(0).getSaleForecastLineItems();
        plannedMonthlyDemand.setSaleForecastA(saleForecastLineItems.get(0).getTotalQuantityInCases());
        plannedMonthlyDemand.setSaleForecastB(saleForecastLineItems.get(1).getTotalQuantityInCases());
        plannedMonthlyDemand.setSaleForecastC(saleForecastLineItems.get(2).getTotalQuantityInCases());
        plannedMonthlyDemand.setSaleForecastD(saleForecastLineItems.get(3).getTotalQuantityInCases());
        em.persist(plannedMonthlyDemand);
        
        plannedMonthlyDemand.setListOfPlannedWeeklyDemand(weeklyProductionPlanBeanLocal.createPlannedWeeklyDemands(month));
        em.flush();
        
        return plannedMonthlyDemand;
    }
    
    public void updatePlannedMonthlyDemand(Long id, Long productionPlan, 
            Long inventoryA, Long inventoryB, Long inventoryC, Long inventoryD, 
            Double breakDownA, Double breakDownB, Double breakDownC, Double breakDownD)
    {
        PlannedMonthlyDemand plannedMonthlyDemand = em.find(PlannedMonthlyDemand.class, id);
        plannedMonthlyDemand.setProductionPlan(productionPlan);
        plannedMonthlyDemand.setInventoryA(inventoryA);
        plannedMonthlyDemand.setInventoryB(inventoryB);
        plannedMonthlyDemand.setInventoryC(inventoryC);
        plannedMonthlyDemand.setInventoryD(inventoryD);
        
        plannedMonthlyDemand.setWorkingHours(0);
        plannedMonthlyDemand.setOvertimeHours(0);
        
        plannedMonthlyDemand.setCapacityAB(new Long(50));
        plannedMonthlyDemand.setCapacityCD(new Long(45));
        
        plannedMonthlyDemand.setBreakDownA(breakDownA);
        plannedMonthlyDemand.setBreakDownB(breakDownB);
        plannedMonthlyDemand.setBreakDownC(breakDownC);
        plannedMonthlyDemand.setBreakDownD(breakDownD);

        //set forecast
            int monthName = Integer.parseInt(plannedMonthlyDemand.getMonthName().substring(0, plannedMonthlyDemand.getMonthName().length() - 5));
            int year = Integer.parseInt(plannedMonthlyDemand.getMonthName().substring(plannedMonthlyDemand.getMonthName().length() - 4));
            int monthIndex = monthName-1;

            List<MonthlySaleForecast> monthlySaleForecast = saleForecastBeanLocal.getMonthlySaleForecasts(year, monthIndex, monthIndex);
            List<SaleForecastLineItem> saleForecastLineItems = monthlySaleForecast.get(0).getSaleForecastLineItems();
            plannedMonthlyDemand.setSaleForecastA(saleForecastLineItems.get(0).getTotalQuantityInCases());
            plannedMonthlyDemand.setSaleForecastB(saleForecastLineItems.get(1).getTotalQuantityInCases());
            plannedMonthlyDemand.setSaleForecastC(saleForecastLineItems.get(2).getTotalQuantityInCases());
            plannedMonthlyDemand.setSaleForecastD(saleForecastLineItems.get(3).getTotalQuantityInCases());

        //set production plans
        if ((productionPlan != null) && (breakDownA != null))
        {
            plannedMonthlyDemand.setProductionPlanA(Math.round((double) productionPlan * breakDownA/100));
        }
        if ((productionPlan != null) && (breakDownB != null))
        {
            plannedMonthlyDemand.setProductionPlanB(Math.round((double) productionPlan * breakDownB/100));
        }
        if ((productionPlan != null) && (breakDownC != null))
        {
            plannedMonthlyDemand.setProductionPlanC(Math.round((double) productionPlan * breakDownC/100));
        }
        if ((productionPlan != null) && (breakDownD != null))
        {
            plannedMonthlyDemand.setProductionPlanD(Math.round((double) productionPlan * breakDownD/100));
        }
        //set utilization
        if ((plannedMonthlyDemand.getProductionPlanA() != null) && (plannedMonthlyDemand.getProductionPlanB() != null)&& (plannedMonthlyDemand.getProductionPlanC() != null)&& (plannedMonthlyDemand.getProductionPlanD() != null))
        {
            Double prodA = (double) plannedMonthlyDemand.getProductionPlanA();
            Double prodB = (double) plannedMonthlyDemand.getProductionPlanB();
            Double prodC = (double) plannedMonthlyDemand.getProductionPlanC();
            Double prodD = (double) plannedMonthlyDemand.getProductionPlanD();
            
            Double temp = ((((prodA + prodB) / plannedMonthlyDemand.getCapacityAB()) + ((prodC + prodD) / plannedMonthlyDemand.getCapacityCD())) 
                    / plannedMonthlyDemand.getTotalCapacity()) * 100;
            plannedMonthlyDemand.setUtilization(Math.round(temp));
        }
        
        //set working days
        plannedMonthlyDemand.setNumberOfWorkingDays(this.getWorkingDaysByMonth(plannedMonthlyDemand.getMonthName()));
        em.persist(plannedMonthlyDemand);
        em.flush();
        
        List<PlannedWeeklyDemand> weeklyDemand = plannedMonthlyDemand.getListOfPlannedWeeklyDemand();
        for (PlannedWeeklyDemand p : weeklyDemand)
        {
            weeklyProductionPlanBeanLocal.updatePlannedWeeklyDemand(p.getId());
        }
        em.flush();
    }
    
    public boolean checkUtilization (Long productionPlan, Long capacity)
    {
        Double utilization = (Double) ((double) productionPlan / (double) capacity);
        if (utilization >= 0.9)
            return false;
        else
            return true;
    }
    
    public Long calculateInventory(Long salesForecast, Long productionPlan, Long previousInventory)
    {
        if (salesForecast == null || productionPlan == null || previousInventory == null)
        {
            return new Long(-1);
        }
        Long inventory = (productionPlan + previousInventory) - salesForecast;
        return inventory;
    }
    
    
    public List<PlannedMonthlyDemand> getPlannedMonthlyDemands() {
        Query q = em.createQuery("SELECT p FROM PlannedMonthlyDemand p");
        List<PlannedMonthlyDemand> list = q.getResultList();
        
        //update sale forecast
        
        
        for (PlannedMonthlyDemand p: list)
        {
            int monthName = Integer.parseInt(p.getMonthName().substring(0, p.getMonthName().length() - 5));
            int year = Integer.parseInt(p.getMonthName().substring(p.getMonthName().length() - 4));
            int monthIndex = monthName-1;

            List<MonthlySaleForecast> monthlySaleForecast = saleForecastBeanLocal.getMonthlySaleForecasts(year, monthIndex, monthIndex);
            List<SaleForecastLineItem> saleForecastLineItems = monthlySaleForecast.get(0).getSaleForecastLineItems();
            p.setSaleForecastA(saleForecastLineItems.get(0).getTotalQuantityInCases());
            p.setSaleForecastB(saleForecastLineItems.get(1).getTotalQuantityInCases());
            p.setSaleForecastC(saleForecastLineItems.get(2).getTotalQuantityInCases());
            p.setSaleForecastD(saleForecastLineItems.get(3).getTotalQuantityInCases());
        }
        
        return list;
    }
    
    public PlannedMonthlyDemand findByMonth(String monthName) {
        Query q = em.createQuery("SELECT p FROM PlannedMonthlyDemand p WHERE p.monthName=:monthName");
        q.setParameter("monthName", monthName);
        //PlannedMonthlyDemand p = (PlannedMonthlyDemand) q.getSingleResult();
        //System.out.println(p.getMonthName());
        return (PlannedMonthlyDemand) q.getSingleResult();
    }
    
    

    public Long getWorkingDaysByMonth(String time)      
    {        
        String month = time.substring(0, time.length() - 5);
        int index = Integer.parseInt(month)-1;
        int year = Integer.parseInt(time.substring(time.length() - 4));
        
        Calendar c = Calendar.getInstance();
        if (index != -1)
        {
            c.set(year, index, 1);
        }
        else
        {
            System.out.println("CANNOT FIND THE MONTH");
        }
        int workingDaysCount = 0;
        while (index == c.get(Calendar.MONTH))
        {
            if (c.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY && c.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)
            {
                workingDaysCount ++;
            }
            c.add(Calendar.DAY_OF_MONTH, 1);
        }
        
        //exclude New Year in Jan, Labour Day in May, National Day in August and Christmas Day in December
        //need to calculate for chinese calendar: chinese new year, good friday, vesak day
        //and islamic calendar: hari raya puasa, hari raya haji, deepavali
        workingDaysCount -= holidayBeanLocal.getHolidayByMonth(time);
        
        return new Long(workingDaysCount);   
    }
    
    public List<String> createMonthList()
    {
        Calendar time = Calendar.getInstance();
        List<String> monthList = new ArrayList<String>();
        for (int i = 0; i < 12; ++i)
        {
            String currentMonth;
            currentMonth = Integer.toString(time.get(Calendar.MONTH) + 1);
            String currentYear;
            currentYear = Integer.toString(time.get(Calendar.YEAR));
            monthList.add(currentMonth + "/" + currentYear);
            time.add(Calendar.MONTH, 1);
        }
        return monthList;
    }
}

